﻿#region Copyright (c) 2012-10, Olaf Kober <amarok.projects@gmail.com>
//================================================================================
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//================================================================================
#endregion

#if TESTS

using System;
using NUnit.Framework;


namespace Amarok
{
	[TestFixture]
	public class Test_BufferSegment
	{
		[Test]
		public void Test_Empty()
		{
			var segment = BufferSegment.Empty;

			Assert.That(segment.Buffer, Is.Not.Null);
			Assert.That(segment.Offset, Is.EqualTo(0));
			Assert.That(segment.Count, Is.EqualTo(0));
			Assert.That(segment.ToString(), Is.EqualTo(String.Empty));
		}

		[Test]
		public void Test_Construction_WithBuffer()
		{
			var buffer = new Byte[] { 0x11, 0x22, 0x33, 0x44 };
			var segment = new BufferSegment(buffer);

			Assert.AreSame(buffer, segment.Buffer);
			Assert.AreEqual(0, segment.Offset);
			Assert.AreEqual(4, segment.Count);
			Assert.That(segment.ToString(), Is.EqualTo("11;22;33;44"));
		}

		[Test]
		public void Test_Construction_WithBufferOffsetCount()
		{
			var buffer = new Byte[] { 0x11, 0x22, 0x33, 0x44 };
			var segment = new BufferSegment(buffer, 1, 3);

			Assert.AreSame(buffer, segment.Buffer);
			Assert.AreEqual(1, segment.Offset);
			Assert.AreEqual(3, segment.Count);
			Assert.That(segment.ToString(), Is.EqualTo("22;33;44"));
		}

		[Test]
		public void Test_Construction_WithZeroLengthBuffer()
		{
			var buffer = new Byte[0];
			var segment = new BufferSegment(buffer, 0, 0);

			Assert.AreSame(buffer, segment.Buffer);
			Assert.AreEqual(0, segment.Offset);
			Assert.AreEqual(0, segment.Count);
			Assert.That(segment.ToString(), Is.EqualTo(""));
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestConstructionWithNullBuffer()
		{
			var segment = new BufferSegment(null, 1, 3);
		}

		[Test]
		[ExpectedException(typeof(ArgumentOutOfRangeException))]
		public void TestConstructionWithOffsetLessThanZero()
		{
			var buffer = new Byte[] { 0x11, 0x22, 0x33, 0x44 };
			var segment = new BufferSegment(buffer, -1, 1);
		}

		[Test]
		[ExpectedException(typeof(ArgumentOutOfRangeException))]
		public void TestConstructionWithCountLessThanZero()
		{
			var buffer = new Byte[] { 0x11, 0x22, 0x33, 0x44 };
			var segment = new BufferSegment(buffer, 1, -1);
		}

		[Test]
		[ExpectedException(typeof(ArgumentOutOfRangeException))]
		public void TestConstructionWithOffsetAndCountOutOfRange()
		{
			var buffer = new Byte[] { 0x11, 0x22, 0x33, 0x44 };
			var segment = new BufferSegment(buffer, 2, 3);
		}

		[Test]
		public void TestGetHashCode()
		{
			Byte[] buffer1 = new Byte[] { 0x11, 0x22, 0x33, 0x44 };
			Byte[] buffer2 = new Byte[] { 0x11, 0x22, 0x33 };

			var a = new BufferSegment(buffer1);
			var b = new BufferSegment(buffer1, 0, 4);
			var c = new BufferSegment(buffer2);
			var d = new BufferSegment(buffer2, 0, 3);
			var e = new BufferSegment(buffer1, 0, 3);
			var f = new BufferSegment(buffer1, 3, 1);
			var g = new BufferSegment(buffer2, 2, 1);

			Assert.AreEqual(true, a.GetHashCode() == a.GetHashCode());
			Assert.AreEqual(true, b.GetHashCode() == b.GetHashCode());
			Assert.AreEqual(true, c.GetHashCode() == c.GetHashCode());
			Assert.AreEqual(true, d.GetHashCode() == d.GetHashCode());
			Assert.AreEqual(true, e.GetHashCode() == e.GetHashCode());
			Assert.AreEqual(true, f.GetHashCode() == f.GetHashCode());
			Assert.AreEqual(true, g.GetHashCode() == g.GetHashCode());

			Assert.AreEqual(true, a.GetHashCode() == b.GetHashCode());
			Assert.AreEqual(false, a.GetHashCode() == c.GetHashCode());
			Assert.AreEqual(false, a.GetHashCode() == d.GetHashCode());
			Assert.AreEqual(false, a.GetHashCode() == e.GetHashCode());
			Assert.AreEqual(false, a.GetHashCode() == f.GetHashCode());
			Assert.AreEqual(false, a.GetHashCode() == g.GetHashCode());

			Assert.AreEqual(true, c.GetHashCode() == d.GetHashCode());
			Assert.AreEqual(false, c.GetHashCode() == g.GetHashCode());
			Assert.AreEqual(false, d.GetHashCode() == e.GetHashCode());
		}

		[Test]
		public void TestObjectBasedEquals()
		{
			var buffer1 = new Byte[] { 0x11, 0x22, 0x33, 0x44 };
			var buffer2 = new Byte[] { 0x11, 0x22, 0x33 };

			Object a = new BufferSegment(buffer1);
			Object b = new BufferSegment(buffer1, 0, 4);
			Object c = new BufferSegment(buffer2);
			Object d = new BufferSegment(buffer2, 0, 3);
			Object e = new BufferSegment(buffer1, 0, 3);
			Object f = new BufferSegment(buffer1, 3, 1);
			Object g = new BufferSegment(buffer2, 2, 1);
			Object h = -123;

			// x.Equals(x) == true
			Assert.AreEqual(true, a.Equals(a));
			Assert.AreEqual(true, b.Equals(b));
			Assert.AreEqual(true, c.Equals(c));
			Assert.AreEqual(true, d.Equals(d));
			Assert.AreEqual(true, e.Equals(e));
			Assert.AreEqual(true, f.Equals(f));
			Assert.AreEqual(true, g.Equals(g));

			// x.Equals(null) == false
			Assert.AreEqual(false, a.Equals((Object)null));
			Assert.AreEqual(false, b.Equals((Object)null));
			Assert.AreEqual(false, c.Equals((Object)null));
			Assert.AreEqual(false, d.Equals((Object)null));
			Assert.AreEqual(false, e.Equals((Object)null));
			Assert.AreEqual(false, f.Equals((Object)null));
			Assert.AreEqual(false, g.Equals((Object)null));

			// x.Equals(y) == y.Equals(x)
			Assert.AreEqual(true, a.Equals(b));
			Assert.AreEqual(a.Equals(b), b.Equals(a));

			Assert.AreEqual(false, a.Equals(c));
			Assert.AreEqual(a.Equals(c), c.Equals(a));

			Assert.AreEqual(false, a.Equals(d));
			Assert.AreEqual(a.Equals(d), d.Equals(a));

			Assert.AreEqual(false, a.Equals(e));
			Assert.AreEqual(a.Equals(e), e.Equals(a));

			Assert.AreEqual(false, a.Equals(f));
			Assert.AreEqual(a.Equals(f), f.Equals(a));

			Assert.AreEqual(false, a.Equals(g));
			Assert.AreEqual(a.Equals(g), g.Equals(a));

			Assert.AreEqual(false, a.Equals(h));
			Assert.AreEqual(a.Equals(h), h.Equals(a));


			Assert.AreEqual(true, c.Equals(d));
			Assert.AreEqual(c.Equals(d), d.Equals(c));

			Assert.AreEqual(false, c.Equals(g));
			Assert.AreEqual(c.Equals(g), g.Equals(c));
		}

		[Test]
		public void TestTypeSafeEquals()
		{
			var buffer1 = new Byte[] { 0x11, 0x22, 0x33, 0x44 };
			var buffer2 = new Byte[] { 0x11, 0x22, 0x33 };

			var a = new BufferSegment(buffer1);
			var b = new BufferSegment(buffer1, 0, 4);
			var c = new BufferSegment(buffer2);
			var d = new BufferSegment(buffer2, 0, 3);
			var e = new BufferSegment(buffer1, 0, 3);
			var f = new BufferSegment(buffer1, 3, 1);
			var g = new BufferSegment(buffer2, 2, 1);

			// x.Equals(x) == true
			Assert.AreEqual(true, a.Equals(a));
			Assert.AreEqual(true, b.Equals(b));
			Assert.AreEqual(true, c.Equals(c));
			Assert.AreEqual(true, d.Equals(d));
			Assert.AreEqual(true, e.Equals(e));
			Assert.AreEqual(true, f.Equals(f));
			Assert.AreEqual(true, g.Equals(g));

			// x.Equals(null) == false
			Assert.AreEqual(false, a.Equals((Object)null));
			Assert.AreEqual(false, b.Equals((Object)null));
			Assert.AreEqual(false, c.Equals((Object)null));
			Assert.AreEqual(false, d.Equals((Object)null));
			Assert.AreEqual(false, e.Equals((Object)null));
			Assert.AreEqual(false, f.Equals((Object)null));
			Assert.AreEqual(false, g.Equals((Object)null));

			// x.Equals(y) == y.Equals(x)
			Assert.AreEqual(true, a.Equals(b));
			Assert.AreEqual(a.Equals(b), b.Equals(a));

			Assert.AreEqual(false, a.Equals(c));
			Assert.AreEqual(a.Equals(c), c.Equals(a));

			Assert.AreEqual(false, a.Equals(d));
			Assert.AreEqual(a.Equals(d), d.Equals(a));

			Assert.AreEqual(false, a.Equals(e));
			Assert.AreEqual(a.Equals(e), e.Equals(a));

			Assert.AreEqual(false, a.Equals(f));
			Assert.AreEqual(a.Equals(f), f.Equals(a));

			Assert.AreEqual(false, a.Equals(g));
			Assert.AreEqual(a.Equals(g), g.Equals(a));


			Assert.AreEqual(true, c.Equals(d));
			Assert.AreEqual(c.Equals(d), d.Equals(c));

			Assert.AreEqual(false, c.Equals(g));
			Assert.AreEqual(c.Equals(g), g.Equals(c));
		}

		[Test]
		public void TestEqualOperator()
		{
			var buffer1 = new Byte[] { 0x11, 0x22, 0x33, 0x44 };
			var buffer2 = new Byte[] { 0x11, 0x22, 0x33 };

			var a = new BufferSegment(buffer1);
			var b = new BufferSegment(buffer1, 0, 4);
			var c = new BufferSegment(buffer2);
			var d = new BufferSegment(buffer2, 0, 3);
			var e = new BufferSegment(buffer1, 0, 3);
			var f = new BufferSegment(buffer1, 3, 1);
			var g = new BufferSegment(buffer2, 2, 1);

			// x == x -> true
#pragma warning disable 1718
			Assert.AreEqual(true, a == a);
			Assert.AreEqual(true, b == b);
			Assert.AreEqual(true, c == c);
			Assert.AreEqual(true, d == d);
			Assert.AreEqual(true, e == e);
			Assert.AreEqual(true, f == f);
			Assert.AreEqual(true, g == g);
#pragma warning restore 1718

			// x == null -> true/false
			Assert.AreEqual(false, a == null);
			Assert.AreEqual(false, b == null);
			Assert.AreEqual(false, c == null);
			Assert.AreEqual(false, d == null);
			Assert.AreEqual(false, e == null);
			Assert.AreEqual(false, f == null);
			Assert.AreEqual(false, g == null);

			// null == x -> true/false
			Assert.AreEqual(false, null == a);
			Assert.AreEqual(false, null == b);
			Assert.AreEqual(false, null == c);
			Assert.AreEqual(false, null == d);
			Assert.AreEqual(false, null == e);
			Assert.AreEqual(false, null == f);
			Assert.AreEqual(false, null == g);

			// x.Equals(y) == y.Equals(x)
			Assert.AreEqual(true, a == b);
			Assert.AreEqual(a == b, b == a);

			Assert.AreEqual(false, a == c);
			Assert.AreEqual(a == c, c == a);

			Assert.AreEqual(false, a == d);
			Assert.AreEqual(a == d, d == a);

			Assert.AreEqual(false, a == e);
			Assert.AreEqual(a == e, e == a);

			Assert.AreEqual(false, a == f);
			Assert.AreEqual(a == f, f == a);

			Assert.AreEqual(false, a == g);
			Assert.AreEqual(a == g, g == a);

			Assert.AreEqual(true, c == d);
			Assert.AreEqual(d == c, c == d);
		}

		[Test]
		public void TestUnequalOperator()
		{
			var buffer1 = new Byte[] { 0x11, 0x22, 0x33, 0x44 };
			var buffer2 = new Byte[] { 0x11, 0x22, 0x33 };

			var a = new BufferSegment(buffer1);
			var b = new BufferSegment(buffer1, 0, 4);
			var c = new BufferSegment(buffer2);
			var d = new BufferSegment(buffer2, 0, 3);
			var e = new BufferSegment(buffer1, 0, 3);
			var f = new BufferSegment(buffer1, 3, 1);
			var g = new BufferSegment(buffer2, 2, 1);

			// x == x -> true
#pragma warning disable 1718
			Assert.AreEqual(false, a != a);
			Assert.AreEqual(false, b != b);
			Assert.AreEqual(false, c != c);
			Assert.AreEqual(false, d != d);
			Assert.AreEqual(false, e != e);
			Assert.AreEqual(false, f != f);
			Assert.AreEqual(false, g != g);
#pragma warning restore 1718

			// x == null -> true/false
			Assert.AreEqual(true, a != null);
			Assert.AreEqual(true, b != null);
			Assert.AreEqual(true, c != null);
			Assert.AreEqual(true, d != null);
			Assert.AreEqual(true, e != null);
			Assert.AreEqual(true, f != null);
			Assert.AreEqual(true, g != null);

			// null == x -> true/false
			Assert.AreEqual(true, null != a);
			Assert.AreEqual(true, null != b);
			Assert.AreEqual(true, null != c);
			Assert.AreEqual(true, null != d);
			Assert.AreEqual(true, null != e);
			Assert.AreEqual(true, null != f);
			Assert.AreEqual(true, null != g);

			// x.Equals(y) == y.Equals(x)
			Assert.AreEqual(false, a != b);
			Assert.AreEqual(a != b, b != a);

			Assert.AreEqual(true, a != c);
			Assert.AreEqual(a != c, c != a);

			Assert.AreEqual(true, a != d);
			Assert.AreEqual(a != d, d != a);

			Assert.AreEqual(true, a != e);
			Assert.AreEqual(a != e, e != a);

			Assert.AreEqual(true, a != f);
			Assert.AreEqual(a != f, f != a);

			Assert.AreEqual(true, a != g);
			Assert.AreEqual(a != g, g != a);

			Assert.AreEqual(false, c != d);
			Assert.AreEqual(d != c, c != d);
		}


		[Test]
		public void Test_Add()
		{
			var segment1 = new BufferSegment(new Byte[] { 0x11, 0x22, 0x33, 0x44, 0x55 }, 1, 3);
			var segment2 = new BufferSegment(new Byte[] { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE }, 2, 2);

			var result = segment1.Add(segment2);

			Assert.That(result.Buffer, Is.Not.SameAs(segment1.Buffer));
			Assert.That(result.Buffer, Is.Not.SameAs(segment2.Buffer));
			Assert.That(result.Offset, Is.EqualTo(0));
			Assert.That(result.Count, Is.EqualTo(5));
			Assert.That(result.Buffer[0], Is.EqualTo(0x22));
			Assert.That(result.Buffer[1], Is.EqualTo(0x33));
			Assert.That(result.Buffer[2], Is.EqualTo(0x44));
			Assert.That(result.Buffer[3], Is.EqualTo(0xCC));
			Assert.That(result.Buffer[4], Is.EqualTo(0xDD));
		}

		[Test]
		public void Test_Add_PlusOperator()
		{
			var segment1 = new BufferSegment(new Byte[] { 0x11, 0x22, 0x33, 0x44, 0x55 }, 1, 3);
			var segment2 = new BufferSegment(new Byte[] { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE }, 2, 2);

			var result = segment1 + segment2;

			Assert.That(result.Buffer, Is.Not.SameAs(segment1.Buffer));
			Assert.That(result.Buffer, Is.Not.SameAs(segment2.Buffer));
			Assert.That(result.Offset, Is.EqualTo(0));
			Assert.That(result.Count, Is.EqualTo(5));
			Assert.That(result.Buffer[0], Is.EqualTo(0x22));
			Assert.That(result.Buffer[1], Is.EqualTo(0x33));
			Assert.That(result.Buffer[2], Is.EqualTo(0x44));
			Assert.That(result.Buffer[3], Is.EqualTo(0xCC));
			Assert.That(result.Buffer[4], Is.EqualTo(0xDD));
		}

		[Test]
		public void Test_Add_EmptyWithData()
		{
			var segment1 = BufferSegment.Empty;
			var segment2 = new BufferSegment(new Byte[] { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE }, 2, 2);

			var result = segment1.Add(segment2);

			Assert.That(result.Buffer, Is.SameAs(segment2.Buffer));
			Assert.That(result.Offset, Is.EqualTo(2));
			Assert.That(result.Count, Is.EqualTo(2));
		}

		[Test]
		public void Test_Add_DataWithEmpty()
		{
			var segment1 = new BufferSegment(new Byte[] { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE }, 2, 2);
			var segment2 = BufferSegment.Empty;

			var result = segment1.Add(segment2);

			Assert.That(result.Buffer, Is.SameAs(segment1.Buffer));
			Assert.That(result.Offset, Is.EqualTo(2));
			Assert.That(result.Count, Is.EqualTo(2));
		}


		[Test]
		public void Test_Discard_ZeroCount()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = segment.Discard(2, 0);

			Assert.That(result.Buffer, Is.SameAs(segment.Buffer));
			Assert.That(result.Offset, Is.EqualTo(segment.Offset));
			Assert.That(result.Count, Is.EqualTo(segment.Count));
		}

		[Test]
		public void Test_Discard_All()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = segment.Discard(0, 5);

			Assert.That(result.Buffer, Is.Not.SameAs(segment.Buffer));
			Assert.That(result.Offset, Is.EqualTo(0));
			Assert.That(result.Count, Is.EqualTo(0));
		}

		[Test]
		public void Test_Discard_FromBegin()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = segment.Discard(0, 2);

			Assert.That(result.Buffer[result.Offset + 0], Is.EqualTo(0xCC));
			Assert.That(result.Buffer[result.Offset + 1], Is.EqualTo(0xDD));
			Assert.That(result.Buffer[result.Offset + 2], Is.EqualTo(0xEE));
			Assert.That(result.Buffer, Is.SameAs(segment.Buffer));
		}

		[Test]
		public void Test_Discard_FromEnd()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = segment.Discard(3, 2);

			Assert.That(result.Buffer[result.Offset + 0], Is.EqualTo(0xAA));
			Assert.That(result.Buffer[result.Offset + 1], Is.EqualTo(0xBB));
			Assert.That(result.Buffer[result.Offset + 2], Is.EqualTo(0xCC));
			Assert.That(result.Buffer, Is.SameAs(segment.Buffer));
		}

		[Test]
		public void Test_Discard_FromNearBegin()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = segment.Discard(1, 2);

			Assert.That(result.Buffer[result.Offset + 0], Is.EqualTo(0xAA));
			Assert.That(result.Buffer[result.Offset + 1], Is.EqualTo(0xDD));
			Assert.That(result.Buffer[result.Offset + 2], Is.EqualTo(0xEE));
			Assert.That(result.Buffer, Is.SameAs(segment.Buffer));
			Assert.That(result.Offset, Is.EqualTo(4));
		}

		[Test]
		public void Test_Discard_FromNearBegin_2()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = segment.Discard(1, 1);

			Assert.That(result.Buffer[result.Offset + 0], Is.EqualTo(0xAA));
			Assert.That(result.Buffer[result.Offset + 1], Is.EqualTo(0xCC));
			Assert.That(result.Buffer[result.Offset + 2], Is.EqualTo(0xDD));
			Assert.That(result.Buffer[result.Offset + 3], Is.EqualTo(0xEE));
			Assert.That(result.Buffer, Is.SameAs(segment.Buffer));
			Assert.That(result.Offset, Is.EqualTo(3));
		}

		[Test]
		public void Test_Discard_FromNearEnd()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = segment.Discard(2, 2);

			Assert.That(result.Buffer[result.Offset + 0], Is.EqualTo(0xAA));
			Assert.That(result.Buffer[result.Offset + 1], Is.EqualTo(0xBB));
			Assert.That(result.Buffer[result.Offset + 2], Is.EqualTo(0xEE));
			Assert.That(result.Buffer, Is.SameAs(segment.Buffer));
			Assert.That(result.Offset, Is.EqualTo(2));
		}

		[Test]
		public void Test_Discard_FromNearEnd_2()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = segment.Discard(3, 1);

			Assert.That(result.Buffer[result.Offset + 0], Is.EqualTo(0xAA));
			Assert.That(result.Buffer[result.Offset + 1], Is.EqualTo(0xBB));
			Assert.That(result.Buffer[result.Offset + 2], Is.EqualTo(0xCC));
			Assert.That(result.Buffer[result.Offset + 3], Is.EqualTo(0xEE));
			Assert.That(result.Buffer, Is.SameAs(segment.Buffer));
			Assert.That(result.Offset, Is.EqualTo(2));
		}

		[Test]
		public void Test_Discard_Offset_Negative()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					segment.Discard(-1, 2);
				});
		}

		[Test]
		public void Test_Discard_Count_Negative()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					segment.Discard(1, -1);
				});
		}

		[Test]
		public void Test_Discard_OffsetCount_Exceed_Segment()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					segment.Discard(4, 2);
				});
		}

		[Test]
		public void Test_Indexer()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);

			Assert.That(segment[0], Is.EqualTo(0xAA));
			Assert.That(segment[1], Is.EqualTo(0xBB));
			Assert.That(segment[2], Is.EqualTo(0xCC));
			Assert.That(segment[3], Is.EqualTo(0xDD));
			Assert.That(segment[4], Is.EqualTo(0xEE));

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					var dummy = segment[-1];
				});

			Assert.Throws<ArgumentOutOfRangeException>(() =>
				{
					var dummy = segment[5];
				});
		}

		[Test]
		public void Test_Clone()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = segment.Clone();

			Assert.That(result.Buffer[result.Offset + 0], Is.EqualTo(0xAA));
			Assert.That(result.Buffer[result.Offset + 1], Is.EqualTo(0xBB));
			Assert.That(result.Buffer[result.Offset + 2], Is.EqualTo(0xCC));
			Assert.That(result.Buffer[result.Offset + 3], Is.EqualTo(0xDD));
			Assert.That(result.Buffer[result.Offset + 4], Is.EqualTo(0xEE));
			Assert.That(result.Buffer, Is.Not.SameAs(segment.Buffer));
			Assert.That(result.Offset, Is.EqualTo(0));
			Assert.That(result.Count, Is.EqualTo(segment.Count));
		}

		[Test]
		public void Test_Clone_ViaInterface()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = (BufferSegment)((ICloneable)segment).Clone();

			Assert.That(result.Buffer[result.Offset + 0], Is.EqualTo(0xAA));
			Assert.That(result.Buffer[result.Offset + 1], Is.EqualTo(0xBB));
			Assert.That(result.Buffer[result.Offset + 2], Is.EqualTo(0xCC));
			Assert.That(result.Buffer[result.Offset + 3], Is.EqualTo(0xDD));
			Assert.That(result.Buffer[result.Offset + 4], Is.EqualTo(0xEE));
			Assert.That(result.Buffer, Is.Not.SameAs(segment.Buffer));
			Assert.That(result.Offset, Is.EqualTo(0));
			Assert.That(result.Count, Is.EqualTo(segment.Count));
		}

		[Test]
		public void Test_Clone_ZeroCount()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 0);
			var result = segment.Clone();

			Assert.That(result, Is.EqualTo(BufferSegment.Empty));
		}

		[Test]
		public void Test_ToArray()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 5);
			var result = segment.ToArray();

			Assert.That(result[0], Is.EqualTo(0xAA));
			Assert.That(result[1], Is.EqualTo(0xBB));
			Assert.That(result[2], Is.EqualTo(0xCC));
			Assert.That(result[3], Is.EqualTo(0xDD));
			Assert.That(result[4], Is.EqualTo(0xEE));
			Assert.That(result, Is.Not.SameAs(segment.Buffer));
			Assert.That(result.Length, Is.EqualTo(segment.Count));
		}

		[Test]
		public void Test_ToArray_ZeroCount()
		{
			var segment = new BufferSegment(new Byte[] { 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x33 }, 2, 0);
			var result = segment.ToArray();

			Assert.That(result, Is.Not.SameAs(segment.Buffer));
			Assert.That(result.Length, Is.EqualTo(segment.Count));
		}

	}
}

#endif
